iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0

今天來研究布林運算的順序,我們從下面的算式開始:

True or True and False
True

上面的算式和以下的算式相等,因為 andor 優先權更高,會先進行運算:

True or (True and False)
True

下面的結果就不同了,因為我們先用括號把 or 包起來運算:

(True or True) and False
False

Short-Circuiting(短路)

假設我們有以下的算式:

a = 10
b = 2

if a/b > 2:
    print('a is at least double b')
a is at least double b

看起來一切OK,但假如 b = 0,就會遇到問題了:

a = 10
b = 0

if a/b > 2:
    print('a is at least double b')
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

/Users/maotingyang/Downloads/Booleans - Precedence and Short-Circuiting.ipynb Cell 11 in <cell line: 4>()
      <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X11sZmlsZQ%3D%3D?line=0'>1</a> a = 10
      <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X11sZmlsZQ%3D%3D?line=1'>2</a> b = 0
----> <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X11sZmlsZQ%3D%3D?line=3'>4</a> if a/b > 2:
      <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X11sZmlsZQ%3D%3D?line=4'>5</a>     print('a is at least double b')


ZeroDivisionError: division by zero

因為 0 是不能當分母的。

這時候我們可以運用「短路」,也就是當 and 左邊不成立時,右邊不會再運算下去。就跟一個串連的電路一樣,當遇到第一個開關斷開,不用管第二個開關的狀態,電路都是不通的:

a = 10
b = 0

if b and a/b > 2:
    print('a is at least double b')

以上的寫法就可以避開分母為 0 的錯誤了。

再來看一個常見的情況,我們從資料庫撈出字串,其中可能有 None 也可能有空字串,怎麼處理?

我們先 import 一個好用的 module:string

import string
help(string)
Help on module string:

NAME
    string - A collection of string constants.

DESCRIPTION
    Public module variables:
    
    whitespace -- a string containing all ASCII whitespace
    ascii_lowercase -- a string containing all ASCII lowercase letters
    ascii_uppercase -- a string containing all ASCII uppercase letters
    ascii_letters -- a string containing all ASCII letters
    digits -- a string containing all ASCII decimal digits
    hexdigits -- a string containing all ASCII hexadecimal digits
    octdigits -- a string containing all ASCII octal digits
    punctuation -- a string containing all ASCII punctuation characters
    printable -- a string containing all ASCII characters considered printable

CLASSES
    builtins.object
        Formatter
        Template
    
    class Formatter(builtins.object)
     |  Methods defined here:
     |  
     |  check_unused_args(self, used_args, args, kwargs)
     |  
     |  convert_field(self, value, conversion)
     |  
     |  format(self, format_string, /, *args, **kwargs)
     |  
     |  format_field(self, value, format_spec)
     |  
     |  get_field(self, field_name, args, kwargs)
     |      # given a field_name, find the object it references.
     |      #  field_name:   the field being looked up, e.g. "0.name"
     |      #                 or "lookup[3]"
     |      #  used_args:    a set of which args have been used
     |      #  args, kwargs: as passed in to vformat
     |  
     |  get_value(self, key, args, kwargs)
     |  
     |  parse(self, format_string)
     |      # returns an iterable that contains tuples of the form:
     |      # (literal_text, field_name, format_spec, conversion)
     |      # literal_text can be zero length
     |      # field_name can be None, in which case there's no
     |      #  object to format and output
     |      # if field_name is not None, it is looked up, formatted
     |      #  with format_spec and conversion and then used
     |  
     |  vformat(self, format_string, args, kwargs)
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  __dict__
     |      dictionary for instance variables (if defined)
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
    
    class Template(builtins.object)
     |  Template(template)
     |  
     |  A string class for supporting $-substitutions.
     |  
     |  Methods defined here:
     |  
     |  __init__(self, template)
     |      Initialize self.  See help(type(self)) for accurate signature.
     |  
     |  safe_substitute(self, mapping={}, /, **kws)
     |  
     |  substitute(self, mapping={}, /, **kws)
     |  
     |  ----------------------------------------------------------------------
     |  Class methods defined here:
     |  
     |  __init_subclass__() from builtins.type
     |      This method is called when a class is subclassed.
     |      
     |      The default implementation does nothing. It may be
     |      overridden to extend subclasses.
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  __dict__
     |      dictionary for instance variables (if defined)
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)
     |  
     |  ----------------------------------------------------------------------
     |  Data and other attributes defined here:
     |  
     |  braceidpattern = None
     |  
     |  delimiter = '$'
     |  
     |  flags = re.IGNORECASE
     |  
     |  idpattern = '(?a:[_a-z][_a-z0-9]*)'
     |  
     |  pattern = re.compile('\n            \\$(?:\n              ...identifie...

FUNCTIONS
    capwords(s, sep=None)
        capwords(s [,sep]) -> string
        
        Split the argument into words using split, capitalize each
        word using capitalize, and join the capitalized words using
        join.  If the optional second argument sep is absent or None,
        runs of whitespace characters are replaced by a single space
        and leading and trailing whitespace are removed, otherwise
        sep is used to split and join the words.

DATA
    __all__ = ['ascii_letters', 'ascii_lowercase', 'ascii_uppercase', 'cap...
    ascii_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
    ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
    ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    digits = '0123456789'
    hexdigits = '0123456789abcdefABCDEF'
    octdigits = '01234567'
    printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU...
    punctuation = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
    whitespace = ' \t\n\r\x0b\x0c'

FILE
    /opt/homebrew/Cellar/python@3.10/3.10.6_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/string.py
string.digits
'0123456789'
string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

我們拿到很常用的「數字大全」和「英文字母大全」,用它們來寫程式94開心:

name = ''
if name[0] in string.digits:
    print('Name cannot start with a digit!')
---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

/Users/maotingyang/Downloads/Booleans - Precedence and Short-Circuiting.ipynb Cell 20 in <cell line: 2>()
      <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X21sZmlsZQ%3D%3D?line=0'>1</a> name = ''
----> <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X21sZmlsZQ%3D%3D?line=1'>2</a> if name[0] in string.digits:
      <a href='vscode-notebook-cell:/Users/maotingyang/Downloads/Booleans%20-%20Precedence%20and%20Short-Circuiting.ipynb#X21sZmlsZQ%3D%3D?line=2'>3</a>     print('Name cannot start with a digit!')


IndexError: string index out of range

啊⋯⋯遇到問題了,對空字串取 indexing 會報錯,怎麼辦呢?

善用「短路」的技巧:

name = ''
if name and name[0] in string.digits:
    print('Name cannot start with a digit!')
name = None
if name and name[0] in string.digits:
    print('Name cannot start with a digit!')
name = 'Bob'
if name and name[0] in string.digits:
    print('Name cannot start with a digit!')
name = '1Bob'
if name and name[0] in string.digits:
    print('Name cannot start with a digit!')
Name cannot start with a digit!

Python村又度過了和平的一天,感謝讀者們的努力,我們明天見~

參考:Python 3: Deep Dive (Part 1 - Functional)


上一篇
Booleans: Truth Values
下一篇
Booleans: Boolean Operators
系列文
小青蛇變大蟒蛇——進階Python學起來!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言